/**
 * Debug-JS Prototype Adapter Plugin.
 *
 * This plugin allows to wrap a set of Prototype framework classes, in order to
 * attach the debugger to all classes in a transparent way, without putting any
 * code inside the application.
 *
 * @author Matias Mirabelli <admin@moyrax.com>
 */
Debugger.Adapter.Prototype = function () {
  /* Default Context for this object */
  var context = new Debugger.Context();

  /**
   * Overrides the constructor of a class.
   *
   * @param aFunction {Function} Class definition.
   */
  var _constructorProxy = function(aFunction) {
    if (!aFunction.prototype) {
      return aFunction;
    }

    var constructor = aFunction.prototype.initialize;

    /* Checks for a Prototype-compatible class */
    if (!constructor) {
      return aFunction;
    }

    /* Wraps the class constructor */
    aFunction.prototype.initialize = Debugger.Utils.wrap(constructor,
                                                         function($super) {
      var _arguments = [];

      for (var i = 1, j = arguments.length; i < j; i++) {
        _arguments.push(arguments[i]);
      }

      /* Attachs the debugger, if it's not attached yet. */
      if (!Debugger.isDebugging(this)) {
        Debugger.attach(this, context);
      }

      /* Executes the original constructor */
      $super.apply(this, _arguments);
    });

    return aFunction;
  };

  /**
   * Attachs PFA to all classes in the given container that matches
   * the specified regexp filter.
   *
   * @param aContainer {Object} Container object.
   * @param nameRegexp {RegExp} Class name filter.
   */
  var _initAdapter = function (aContainer, nameRegexp) {
    for (var property in aContainer) {
      if (aContainer.hasOwnProperty(property)) {
        if (typeof aContainer[property] == "object") {
          _initAdapter(aContainer[property], nameRegexp);
        }

        if (!nameRegexp) {
          nameRegexp = /.*/;
        }

        if (typeof aContainer[property] == "function" &&
            nameRegexp.test(property)) {
          aContainer[property] = _constructorProxy(aContainer[property]);
        }
      }
    }
  };

  var publicInterface = {
    /**
     * Attachs PFA to all classes in the given container that matches
     * the specified regexp filter. If no filter is specified, this
     * method will act in all classes.
     *
     * @param aContainer {Object} Container object.
     * @param nameRegexp {RegExp} Class name filter.
     */
    setup : function(aContainer, nameRegexp) {
      /* Forces the attachment in a specific class */
      if (typeof aContainer == "function") {
        aContainer = _constructorProxy(aContainer);
      } else {
      /* Attach PFA to all clases in the container */
        _initAdapter(aContainer, nameRegexp);
      }
    },

    /**
     * Adds a new exception handler to the adapter.
     *
     * @param eventHandler {Function} Exception handler callback.
     */
    addErrorHandler : function(eventHandler) {
      context.addHandler(Debugger.Events.ERROR, eventHandler);
    }
  };

  return publicInterface;
}();
